/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is COID http service.
 *
 * The Initial Developer of the Original Code is
 * PosAm.
 * Portions created by the Initial Developer are Copyright (C) 2005
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 * Brano Kemen
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */
 
#include "webtalk.h"
#include "core.h"

static hash_keyset<WebtalkCore, _Select_Copy<WebtalkCore,token> > STcores;
static comm_mutex STmutexcores;

////////////////////////////////////////////////////////////////////////////////
net_fnc_s opcd Webtalk::accept_connect( net_in const charstr& path, net_in const charstr& name, net_in const password& pwd, net_out uint* pos )
{
    account_id acid;
    acid._name = name;
    acid._domain = "webtalk";
    acid._pwd = pwd;
    opcd e = _cmdin->set_identity(acid,true);
    if(e)  return e;

    _id = acid._uniqid;
    _name.takeover(acid._name);
    _name << ": ";

    _wc = 0;
    {
        GUARDTHIS(STmutexcores);
        _wc = (WebtalkCore*) STcores.find_value(path);
        if(!_wc) {
            _wc = STcores.insert_value_slot(path);
            _wc->set_board(path);
        }
    }

    bool msg=true;
    {
        GUARDTHIS(_wc->_mutex);
        msg = _wc->add_user(name,_id);

        *pos = (uint)_wc->get_current_pos();
        _usrchng = *pos - 1;

        if( !_wc->is_smiley_configured() )
        {
            charstr buf;
            _cmdin->get_working_dir(buf);
            buf << "smiley.conf";
            _wc->conf_smileys( buf );
        }
    }

    if(msg)
    {
        charstr t;
        t << "<span class=\"tsys\">User " << name << " logged in at ";
        append_time(t);
        t << "</span>";
        send_sysmsg(t);
    }

    return 0;
}

////////////////////////////////////////////////////////////////////////////////
net_fnc_s opcd Webtalk::accept_destroy()
{
    if(!_wc)  return 0;

    _name.resize(-2);
    bool msg=true;
    {
        GUARDTHIS(_wc->_mutex);
        msg = _wc->del_user(_name,_id);
    }

    if(msg)
    {
        charstr t;
        t << "<span class=\"tsys\">User " << _name << " logged out at ";
        append_time(t);
        t << "</span>";
        send_sysmsg(t);
    }

    return 0;
}

////////////////////////////////////////////////////////////////////////////////
net_fnc net_meta opcd Webtalk::read( net_inout uint& ref, net_out dynarray<token>& rows, net_out uint* flg )
{
    uint usrchng;

    _cmdin->request_autodestroy( SESSION_TIMEOUT );

    GUARDTHIS(_wc->_mutex);
    ref = _wc->read( _id, ref, rows, &usrchng );

    *flg = 0;
    if( usrchng != _usrchng )
        *flg = 1;
    //_usrchng = usrchng;

    return 0;
}

////////////////////////////////////////////////////////////////////////////////
net_fnc net_meta opcd Webtalk::send( charstr& text )
{
    token tt = text;
    token towho = tt.cut_left(" \t:", token::cut_trait_keep_sep_default_empty());
    if( tt.first_char() == ':' ) {
        char c = tt.nth_char(1);
        if( isalnum(c) || c==0 || c==' ' || c=='\t' || c=='\r' || c=='\n' )
            ++tt;
        else
            towho.set_empty();
    }
    else
        towho.set_empty();

    _buf.reset();
    append_time(_buf);
    if( towho.is_empty() )
        _buf << " <span class=\"tuser\">" << _name << "</span>";
    else
        _buf << " <span class=\"tpriv\">" << _name << "</span>";
    check_html( text, _buf );

    GUARDTHIS(_wc->_mutex);
    return _wc->add( _id, towho, _buf );
}

////////////////////////////////////////////////////////////////////////////////
net_fnc net_meta opcd Webtalk::userlist( net_out charstr& usrs )
{
    GUARDTHIS(_wc->_mutex);
    _wc->get_usrlist(usrs);
    _usrchng = _wc->get_usrchng();
    return 0;
}

////////////////////////////////////////////////////////////////////////////////
net_fnc net_meta opcd Webtalk::smiles( net_fetch const dynarray<Smiley>*& smi )
{
    GUARDTHIS(_wc->_mutex);
    smi = &_wc->get_smileys();
    return 0;
}



////////////////////////////////////////////////////////////////////////////////
charstr& Webtalk::append_time( charstr& buf )
{
    buf << "<span class=\"tdate\">";
    buf.append_date_local( ::time(0), charstr::DATE_HHMMSS );
    buf << "</span>";
    return buf;
}

////////////////////////////////////////////////////////////////////////////////
opcd Webtalk::send_sysmsg( charstr& text )
{
    GUARDTHIS(_wc->_mutex);
    _wc->add( _id, token::empty(), text );
    return 0;
}

////////////////////////////////////////////////////////////////////////////////
bool Webtalk::check_smiley( token& text, charstr& dst )
{
    token t = text;

    const dynarray<Smiley>* sma;
    { GUARDTHIS(_wc->_mutex);  sma = &_wc->get_smileys(); }

    uints pos = sma->lower_boundT(t);
    if( pos < (*sma).size() && t.begins_with((*sma)[pos].code) )
    {
        text.shift_start( (*sma)[pos].code.len() );
        token t = (*sma)[pos].path;
        dst += t;
        return true;
    }
    else if( pos>0 && t.begins_with((*sma)[pos-1].code) )
    {
        text.shift_start( (*sma)[pos-1].code.len() );
        token t = (*sma)[pos-1].path;
        dst += t;
        return true;
    }
    return false;
}

////////////////////////////////////////////////////////////////////////////////
void Webtalk::check_html( token text, charstr& dst )
{
    for(;;)
    {
        token head = text.cut_left("<>&*_:;hfw", token::cut_trait_keep_sep_with_source());
        dst += head;
        if( text.is_empty() )  break;

        char fc = text.first_char();
        if( fc == ':' || fc == ';' ) {
            if( !check_smiley( text, dst ) )
                dst << fc, ++text;
            continue;
        }

        if( (fc == 'w' || fc=='h' || fc=='f') )
        {
            static token http = "http://";
            static token https = "https://";
            static token ftp  = "ftp://";
            static token ftp2  = "ftp.";
            static token www = "www.";

            if( text.begins_with(http) || text.begins_with(https) || text.begins_with(ftp) || text.begins_with(ftp2) || text.begins_with(www) ) {
                make_href( text, dst );
                continue;
            }
        }

        ++text;
        if( fc == '>' )
            dst += "&gt;";
        else if( fc == '<' )
            dst += "&lt;";
        else if( fc == '&' )
            dst += "&amp;";
        else if( fc == '*' || fc == '_' )
        {
            if( !text.char_is_alpha(0) )  { dst<<fc;  continue; }

            const char* p = text.ptr();
            bool eat=false;
            uint i;
            for( i=0; i<text.len(); ++i )
            {
                char c = p[i];
                if( c == fc ) {
                    if( text.nth_char(i-1) != ' ' )  
                        insert_fmt( dst, fc, text, i );
                    else
                        eat=true;
                    break;
                }
                if( !is_alphanum(c) && c!=' ' )
                {
                    eat=true;
                    break;
                }
            }

            if(eat) {
                dst.add_from( text.ptr()-1, i+1 );
                text.shift_start(i);
            }
        }
        else
            dst += fc;
    }
}

////////////////////////////////////////////////////////////////////////////////
void Webtalk::make_href( token& text, charstr& dst )
{
    token link = text.cut_left(' ', token::cut_trait_keep_sep_with_source());
    char c = link.last_char();
    if( !is_alphanum(c) && c!='_' )
        link--;
    dst << "<a href=\"" << link << "\" target=\"_blank\">" << link << "</a>";
}

////////////////////////////////////////////////////////////////////////////////
uints Webtalk::skip_nested_tags( const token& text )
{
    int nest = 1;
    uints offs=0;
    while( nest>0 )
    {
        offs += text.count_notingroup("<>",offs);

        if( offs >= text.len() ) break;
        if( text.nth_char(offs) == '<' )        ++nest;
        else if( text.nth_char(offs) == '>' )   --nest;
        ++offs;
    }

    return offs;
}
